package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.maiji.cloud.entities.manager.User;
import com.maiji.cloud.entities.manager.UserRole;
import com.maiji.cloud.mapper.UserMapper;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.request.manager.UserAddReqData;
import com.maiji.cloud.request.manager.UserUpdReqData;
import com.maiji.cloud.response.BaseMetaResDto;
import com.maiji.cloud.response.BaseResDto;
import com.maiji.cloud.response.ResMetaData;
import com.maiji.cloud.response.Status;
import com.maiji.cloud.response.manager.UserResData;
import com.maiji.cloud.service.UserRoleService;
import com.maiji.cloud.service.UserService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.eclipse.jetty.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleService userRoleService;

    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        User user = userMapper.findUserByName(name);
        if (user == null) throw new UsernameNotFoundException("用户名不对");
        return user;
    }

    @Override
    public BaseMetaResDto<List<UserResData>> findAllUsers(String roleId, String userName, Boolean eqRoleId, ReqMetaData metaData) {
        EntityWrapper<User> entityWrapper = new EntityWrapper<>();
        if (StringUtil.isNotBlank(roleId)) {
            List<String> userIds = userRoleService.selectList(new EntityWrapper<UserRole>().eq("role_id", roleId))
                    .parallelStream().map(UserRole::getUserId).collect(Collectors.toList());
            if (userIds.size() > 0) {
                if (eqRoleId) entityWrapper.in("uu_id", userIds);
                else entityWrapper.notIn("uu_id", userIds);
            }
        }
        if (StringUtil.isNotBlank(userName)) entityWrapper.like("name", userName);
        Page<User> rolePage = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<UserResData> data = userRoleService.findAllWithRoles(rolePage.getRecords());
        ResMetaData resMetaData = new ResMetaData(rolePage.getCurrent(), rolePage.getSize(), rolePage.getTotal());
        return new BaseMetaResDto<List<UserResData>>(Status.SUCCESS).setData(data).setResMetaData(resMetaData);
    }

    @Override
    public BaseResDto updUser(UserUpdReqData data) {
        String userId = data.getUuId();
        if (StringUtil.isBlank(userId)) return new BaseResDto(Status.ERROR);
        User user = new User().setUuId(userId);
        String pwdOld = data.getPwdOld();
        String pwdNew = data.getPwdNew();
        if (StringUtil.isNotBlank(pwdOld) && StringUtil.isNotBlank(pwdNew)) {
            user = selectOne(new EntityWrapper<User>().eq("uu_id", userId));
            if (user == null) return new BaseResDto(Status.ERROR);
            if (! new BCryptPasswordEncoder().matches(pwdOld, user.getPassword()))
                return new BaseResDto(Status.PWDOLDERROR);
            user.setPwd(new BCryptPasswordEncoder().encode(pwdNew));
        }
        if (BooleanUtils.isTrue(data.getResetPwd())) user.setPwd(new BCryptPasswordEncoder().encode("123456"));
        String executePwd = data.getExecutePwd();
        if (StringUtil.isNotBlank(executePwd)) user.setExecutePwd(new BCryptPasswordEncoder().encode(data.getExecutePwd()));
        if (BooleanUtils.isTrue(data.getDelEPwd())) {
            Wrapper<User> wrapper = new EntityWrapper<User>().eq("uu_id", userId);
            if (! updateForSet("execute_pwd = null", wrapper))
                return new BaseResDto(Status.ERROR);
            else return new BaseResDto(Status.SUCCESS);
        }
        String name = data.getName();
        if (StringUtil.isNotBlank(name)) user.setName(name);
        Boolean usable = data.getUsable();
        if (usable != null) user.setUsable(usable);
        Boolean onlyRead = data.getOnlyRead();
        if (onlyRead != null) user.setOnlyRead(onlyRead);
        if (! updateById(user)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto addUser(UserAddReqData data) {
        User user = new User()
                .setUuId(UUID_MD5.getUUID())
                .setName(data.getName())
                .setPwd(new BCryptPasswordEncoder().encode(data.getPwd()))
                .setExecutePwd(new BCryptPasswordEncoder().encode(data.getExecutePwd()))
                .setOnlyRead(data.getOnlyRead())
                .setUsable(true)
                .setAddDate(new Date());
        if (! insert(user)) return new BaseResDto(Status.ERROR);
        List<String> roleIds = data.getRoleIds();
        if (roleIds != null && roleIds.size() > 0) {
            List<UserRole> userRoleList = roleIds.parallelStream().map(roleId ->
                    new UserRole().setUuId(UUID_MD5.getUUID()).setUserId(user.getUuId()).setRoleId(roleId)).collect(Collectors.toList());
            if (! userRoleService.insertBatch(userRoleList)) return new BaseResDto(Status.ERROR);
        }
        return new BaseResDto(Status.SUCCESS);
    }

}
